package unit17.interruptible;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.Scanner;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class InterruptibleSocketFrame extends JFrame {
	public static  final int TEXT_ROWS=20;
	public static final int TEXT_COLUMNS=60;
			
	private Scanner in;
	private JButton interruptibleButton;
	private JButton BlockingButton;
	private JButton canelButton;
	private JTextArea messages;
	private TestServer server;
	private Thread thread;
	
	
	
	public InterruptibleSocketFrame() {
		JPanel northPanel=new JPanel();
		add(northPanel,BorderLayout.NORTH);
		
		messages=new JTextArea(TEXT_ROWS,TEXT_COLUMNS);
		add(new JScrollPane(messages));
		
		interruptibleButton=new JButton("Interruptible");
		BlockingButton=new JButton("Blocking");
		northPanel.add(interruptibleButton);
		northPanel.add(BlockingButton);
		
		interruptibleButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				interruptibleButton.setEnabled(false);
				BlockingButton.setEnabled(false);
				canelButton.setEnabled(true);
				thread=new Thread(new Runnable() {
					@Override
					public void run() {
						// TODO Auto-generated method stub
						try {
							connectInterruptibly();
						} catch (Exception e2) {
							// TODO: handle exception
							messages.append("\nInterruptibleSocketTest.connectInterruptibly:"+e2);
						}
					}
				});
				thread.start();
			}
		});
		BlockingButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				interruptibleButton.setEnabled(false);
				BlockingButton.setEnabled(false);
				canelButton.setEnabled(true);
				thread=new Thread(new Runnable() {
					@Override
					public void run() {
						// TODO Auto-generated method stub
						try {
							connectBlocking();
						} catch (Exception e2) {
							// TODO: handle exception
							messages.append("\nInterruptibleSocketTest.connectBlocking:"+e2);
						}
					}
				});
				thread.start();
			}
		});
		canelButton=new JButton("Canel");
		canelButton.setEnabled(false);
		northPanel.add(canelButton);
		canelButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				thread.interrupt();
				canelButton.setEnabled(false);
			}
		});
		server=new TestServer();
		new Thread(server).start();
		pack();
	}
	/**
	 * 
	 * @throws IOException
	 */
	private void connectInterruptibly() throws IOException {
		messages.append("Interruptible:\n");
		try(SocketChannel channel=SocketChannel.open(new InetSocketAddress("localhost",8189))){
			in=new Scanner(channel);
			while(!Thread.currentThread().isInterrupted()){
				messages.append("Reading ");
				if(in.hasNextLine()){
					String line=in.nextLine();
					messages.append(line);
					messages.append("\n");
				}
			}
		}finally{
			EventQueue.invokeLater(new Runnable() {
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					messages.append("Channel closed\n");
					interruptibleButton.setEnabled(true);
					BlockingButton.setEnabled(true);
				}
			});
		}

	}
	
	private void connectBlocking() throws IOException {
		// TODO Auto-generated method stub
		messages.append("Blocking:\n");
		try(Socket sock=new Socket("localhost", 8189)){
			in=new Scanner(sock.getInputStream());
			while(!Thread.currentThread().isInterrupted()){
				messages.append("Reading ");
				if(in.hasNextLine()){
					String line=in.nextLine();
					messages.append(line);
					messages.append("\n");
				}
			}
		}finally{
			EventQueue.invokeLater(new Runnable() {
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					messages.append("Socket closed\n");
					interruptibleButton.setEnabled(true);
					BlockingButton.setEnabled(true);
				}
			});
		}
	}
	class TestServer implements Runnable{

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				ServerSocket s=new ServerSocket(8189);
				
				while(true){
					Socket incoming=s.accept();
					Runnable r=new TestServerHandler(incoming);
					Thread t=new Thread(r);
					t.start();
				}
			} catch (Exception e) {
				// TODO: handle exception
				messages.append("\nTestServer.run:"+e);
			}
		}
	}
	class TestServerHandler implements Runnable{
		private Socket incoming;
		private int counter;
		public TestServerHandler(Socket incoming) {
			// TODO Auto-generated constructor stub
			this.incoming=incoming;
		}
		@Override
		public void run() {
			// TODO Auto-generated method stub
			try{
				try{
					OutputStream outputStream=incoming.getOutputStream();
						PrintWriter out=new PrintWriter(outputStream,true/*autoFlush*/);
						while(counter<100){
							counter++;
							if(counter<=10)
								out.println(counter);
							Thread.sleep(100);
						}
					}finally{
						incoming.close();
						messages.append("closing server\n");
					}
				}catch (Exception e) {
					// TODO: handle exception
					messages.append("\nTestServerHandler.run:"+e);
				}
		}
	}
}
